package org.cobaya.commons;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.Reader;
import java.io.Writer;

public class IO {

	public static final String USER_DIR = System.getProperty("user.dir");
	public static final String JAVA_IO_TMPDIR = System.getProperty("java.io.tmpdir");
	public static final String UTF_8 = "UTF-8";

	public static final String PREFIX_CLASSPATH = "classpath:";
	public static final String PREFIX_USERDIR = "userdir:";
	public static final String PREFIX_JAVA_IO_TMPDIR = "tmpdir:";

	public static void assertFileExists(File file) throws IOException {
		Assert.notNull(file, "file must not be null");
		if (!file.exists()) {
			throw new FileNotFoundException(file + " does not exist");
		}
	}

	public static void assertFileReadable(File file) throws IOException {
		assertFileExists(file);
		if (!file.canRead()) {
			throw new IOException(file + " cannot be read");
		}
	}

	public static void assertIsFile(File file) throws IOException {
		assertFileExists(file);
		if (!file.isFile()) {
			throw new IOException(file + " is not a file");
		}
	}

	public static void assertIsDirectory(File file) throws IOException {
		assertFileExists(file);
		if (!file.isDirectory()) {
			throw new IOException(file + " is not a directory");
		}
	}

	public static void assertFileExtension(File file, String extension) throws IOException {
		assertIsFile(file);
		String path = file.getAbsolutePath();
		Assert.isEndsWith(path, extension, file + " is not a " + extension + " file");
	}

	public static InputStream openInputStream(String path) throws IOException {
		return openInputStream(openFile(path));
	}

	public static InputStream openInputStream(File file) throws IOException {
		assertFileReadable(file);
		return new FileInputStream(file);
	}

	public static String transferToPath(String path) {
		Assert.notBlank(path, "path must not be blank");
		if (path.startsWith(PREFIX_CLASSPATH)) {
			String classpath = IO.class.getClassLoader().getResource("").getPath();
			classpath = classpath.substring(0, classpath.length() - 1);
			return classpath + preparePath(path.replaceAll(PREFIX_CLASSPATH, ""));
		}
		if (path.startsWith(PREFIX_USERDIR)) {
			return USER_DIR + preparePath(path.replaceAll(PREFIX_USERDIR, ""));
		}
		if (path.startsWith(PREFIX_JAVA_IO_TMPDIR)) {
			return JAVA_IO_TMPDIR + preparePath(path.replaceAll(PREFIX_JAVA_IO_TMPDIR, ""));
		}
		return path;
	}

	private static String preparePath(String path) {
		if (!path.startsWith("/")) {
			path = "/" + path;
		}
		return path;
	}

	public static File openFile(String path) throws IOException {
		Assert.notBlank(path, "path must not be blank");
		return new File(transferToPath(path));
	}

	public static Writer openWriter(File file) throws IOException {
		Assert.notNull(file, "file must not be null");
		return new FileWriter(file);
	}

	public static Writer openWriter(String path) throws IOException {
		return openWriter(openFile(path));
	}

	public static void closeWriter(Writer writer) throws IOException {
		if (writer != null) {
			writer.flush();
			writer.close();
		}
	}

	public static void closeInputStream(InputStream inputStream) throws IOException {
		if (inputStream != null) {
			inputStream.close();
		}
	}

	public static void closeOutputStream(OutputStream outputStream) throws IOException {
		if (outputStream != null) {
			outputStream.flush();
			outputStream.close();
		}
	}

	public static Reader openReader(File file) throws IOException {
		assertFileReadable(file);
		return new FileReader(file);
	}

	public static void closeReader(Reader reader) throws IOException {
		if (reader != null) {
			reader.close();
		}
	}

	public static boolean deleteFile(File file) {
		Assert.notNull(file, "file must not be null");
		if (file.exists() && file.isFile()) {
			return file.delete();
		}
		return false;
	}

	public static boolean deleteFile(String path) throws IOException {
		return deleteFile(openFile(path));
	}

	public static String changeExtension(String path, String extension) {
		Assert.notBlank(path, "path must not be blank");
		Assert.notBlank(extension, "extension must not be blank");
		return path.substring(0, path.lastIndexOf(".")).concat(".").concat(extension);
	}
}